/**
 * @brief 配置文件DOM
 * @version 1.0
 * @author 宋炜
 * @date 2023-11-16
 */

#pragma once
#include <vector>
#include <string>

#include "designM/composite.hpp"
#include "container/variant.hpp"

namespace wheels
{
	namespace private__{
		struct stDOMItem
		{
			std::string    m_name;
			variant        m_data;

			template< typename DATA_TYPE >
			stDOMItem( const std::string& name , DATA_TYPE&& data ):m_name( name ){
				m_data = variant::make( std::forward< DATA_TYPE >( data ) );
			}

			stDOMItem( const stDOMItem& b ):m_name( b.m_name ) , m_data( b.m_data ){}
			stDOMItem( const stDOMItem& b ):m_name( std::move( b.m_name ) ) , m_data( std::move( b.m_data )){}
			
			stDOMItem& operator=( const stDOMItem& b ){
				m_name = b.m_name;
				m_data = b.m_data;
				return *this;
			}

			stDOMItem& operator=( stDOMItem&& b ){
				m_name = std::move( b.m_name );
				m_data = std::move( b.m_data );
				return *this;
			}
		};

		class path
		{
		public:

		private:
			std::vector< std::string >   m_steps__;
		private:

		public:

			path( const std::string& path );
			path(){}
			~path(){}

			bool operator()( const std::string& path );
			/**
			 * @brief 判断路径是否是相对路径
			 * @return 如果是相对路径返回true,否则返回false
			 */
			bool isRelative();
			/**
			 * @brief 路径合并，
			 */
			path& operator+( const path b );
			/**
			 * @brief 单步的路径名称
			 */
			std::string& operator[]( size_t idx );
			/**
			 * @brief 路径长度。
			 * @return 返回路径长度；在相对路径的情况下并不是实际的路径长度
			 */
			size_t length();
			/**
			 * @brief 获取完整的路径字符串
			 * @return 
			 */
			std::string fullPath();
		};
	}
	
	class confDOM : public dm:composite< stDOMItem >
	{
	public:
		using data_t = stDOMItem;
		using iterator = dm:composite< stDOMItem >::children_t::iterator;
	private:
		private__::path   m_current__;
	public:
		confDOM();
		virtual ~confDOM(){}
		/**
		 * @brief 获取数据。
		 * @tparam 期望的变量类型
		 * @param 变量路径 ,变量路径支持相对路径和绝对路径，分隔符号使用"/"
		 * @return 如果变量存在返回变量值
		 * @exception 如果变量不存在抛出std::runtime_error
		 */
		template< typename TYPE_T >
		TYPE_T get( const std::string& path ){
			TYPE_T ret;

			private__::path p( path );
			if( p.isRelative() ){
				p = m_current__ + p;
			}
			size_t idx = 0;
			bool find = false;
			dm::composite< stDOMItem >   * p_item = this;
			do{
				p_item->for_each( [=]( dm:composite< stDOMItem > * item ){
					if( !item ) return;
					auto * pitem = item->get();
					if( pitem->m_name == p[ idx ] ){
						p_item = item;
						find = true;
						return false;
					}

					return true;
				});
				idx ++;
			}while( idx < p.length() && find);

			if( find && idx == p.length() ){
				ret = p_item->m_data.get<TYPE_T>();
			}else{
				throw std::runtime_error( "数据不存在" );
			}
			return ret;
		}

		/**
		 * @brief 修改变量值。如果变量不存在则增加变量
		 * @tparam TYPE_T
		 * @param path
		 * @param data
		 */
		template< typename TYPE_T >
		void set( const std::string& path , TYPE_T&& data ){
			private__::path p( path );
			if( p.isRelative() ){
				p = m_current__ + p;
			}
			size_t idx = 0;
			bool find = false;
			dm::composite< stDOMItem >   * p_item = this;
			do{
				p_item->for_each( [=]( dm:composite< stDOMItem > * item ){
					if( !item ) return;
					auto * pitem = item->get();
					if( pitem->m_name == p[ idx ] ){
						p_item = item;
						find = true;
						return false;
					}

					return true;
				});

				idx ++;
			}while( idx < p.length() && find );

			if( find && idx == p.length() ){
				ret = p_item->m_data.set( data );
			}else if( idx == p.length() ){ // 如果找不到则添加内容
				std::shared_ptr< stDOMItem > item = std::make_shared<stDOMItem>( p[ idx ] , data );
				p_item->add( item );
			}else{
				throw std::runtime_error( "指定路径内容不存在" );
			}
		}
		/**
		 * @brief 切换当前的路径
		 */
		bool cd( const std::string& path );

		std::string pwd();
	};
}
